/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package stub;

import business.Servidor;
import java.io.EOFException;
import java.io.File;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.SocketException;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author nacho
 */
public class ProcesarMensaje extends Thread {

    Socket socketCliente;

    public ProcesarMensaje(Socket socketCliente) {
        this.socketCliente = socketCliente;
    }

    @Override
    public void run() {
        Servidor servidor = new Servidor();
        File archivo;
        int fd = 0;
        Mensaje mensaje, respuesta;
        String nombreArchivo;

        try {
            mensaje = receive(socketCliente);
            System.out.println("El cliente conectado en el puerto: " + socketCliente.getPort() + " hace operación: " + Protocolo.getInstance().desempaquetarCodOp(mensaje));
            Thread.sleep(2000);
            switch (Protocolo.getInstance().desempaquetarCodOp(mensaje)) {
                case Protocolo.RFS_OPEN:
                    archivo = servidor.open(Protocolo.getInstance().desempaquetarNombreArchivo(mensaje), Protocolo.getInstance().desempaquetarWrite(mensaje));
                    if (archivo != null) {
                        OpenFile fila = new OpenFile(archivo, archivo.getName());
                        //System.out.println("Antes de tabla");
                        fd = Stub.tabla.add(fila);
                        //System.out.println("File descripto que devuelvo: " + fd);
                        respuesta = Protocolo.getInstance().empaquetar(Protocolo.RFS_OPEN, "", Protocolo.OK, fd);
                    } else {
                        if (Protocolo.getInstance().desempaquetarWrite(mensaje)) {
                            respuesta = Protocolo.getInstance().empaquetar(Protocolo.RFS_OPEN, Protocolo.FILE_FOUND);
                        } else {
                            respuesta = Protocolo.getInstance().empaquetar(Protocolo.RFS_OPEN, Protocolo.FILE_NOT_FOUND);
                        }
                    }
                    ///net.send(respuesta);
                    send(socketCliente, respuesta);
                    break;

                case Protocolo.RFS_READ:
                    nombreArchivo = Protocolo.getInstance().desempaquetarNombreArchivo(mensaje);
                    fd = Protocolo.getInstance().desempaquetarArchivo(mensaje);
                    //System.out.println("Fd que vino desde el cliente: " + fd);
                    //System.out.println("nombre de archivo: " + nombreArchivo);
                    if (checkFile(fd, nombreArchivo)) {
                        OpenFile fila = Stub.tabla.get(fd);
                        long aux = fila.getSeek();
                        byte[] data = new byte[Protocolo.TAMANIO_BLOQUE];
                        fila = servidor.read(fila, data);
                        //System.out.println("texto: " + new String(data));
                        aux = fila.getSeek() - aux;
                        //System.out.println("Codigo: " + Protocolo.RFS_READ);
                        respuesta = Protocolo.getInstance().empaquetar(Protocolo.RFS_READ, "", Protocolo.OK, data, aux);
                    } else {
                        System.out.println("algun error sucedio");
                        respuesta = Protocolo.getInstance().empaquetar(Protocolo.RFS_READ, Protocolo.FILE_NOT_FOUND);
                    }
                    // net.send(respuesta);
                    send(socketCliente, respuesta);
                    break;

                case Protocolo.RFS_WRITE:
                    nombreArchivo = Protocolo.getInstance().desempaquetarNombreArchivo(mensaje);
                    fd = Protocolo.getInstance().desempaquetarArchivo(mensaje);
                    if (checkFile(fd, nombreArchivo)) {
                        OpenFile fila = Stub.tabla.get(fd);
                        byte[] data = Protocolo.getInstance().desempaquetarData(mensaje);
                        long cargaUtil = Protocolo.getInstance().desempaquetarLongitudData(mensaje);
                        servidor.write(fila, data, (int) cargaUtil);
                        respuesta = Protocolo.getInstance().empaquetar(Protocolo.RFS_WRITE, Protocolo.OK);
                    } else {
                        respuesta = Protocolo.getInstance().empaquetar(Protocolo.RFS_WRITE, Protocolo.FILE_NOT_FOUND);
                    }
                    //net.send(respuesta);
                    send(socketCliente, respuesta);
                    break;

                case Protocolo.RFS_CLOSE:
                    nombreArchivo = Protocolo.getInstance().desempaquetarNombreArchivo(mensaje);
                    fd = Protocolo.getInstance().desempaquetarArchivo(mensaje);
                    if (checkFile(fd, nombreArchivo)) {
                        Stub.tabla.remove(fd);
                        respuesta = Protocolo.getInstance().empaquetar(Protocolo.RFS_CLOSE, Protocolo.OK);
                    } else {
                        respuesta = Protocolo.getInstance().empaquetar(Protocolo.RFS_CLOSE, Protocolo.FILE_NOT_FOUND);
                    }
                    //net.send(respuesta);
                    send(socketCliente, respuesta);
                    break;
            }
            //}
            //net.close();
            socketCliente.close();
        } catch (InterruptedException ex) {
            Logger.getLogger(Stub.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(Stub.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

    public static void send(Socket cliente,Mensaje mensaje) {
        try {
            if (cliente.isConnected()) {
                // preparo todo para el envio del mensaje
                ObjectOutputStream flujo = new ObjectOutputStream(cliente.getOutputStream());

                flujo.flush();
                flujo.writeObject(mensaje);
                flujo.flush();

            }
        } catch (IOException ex) {
            System.err.println("#####################\n");
            System.err.println(ex.getMessage());
            ex.printStackTrace();
            System.err.println("#####################\n");
        }
    }

    private static Mensaje receive(Socket cliente) throws SocketException, IOException {
        Mensaje mensaje = new Mensaje();
        if (cliente.isConnected()) {
            try {
                // preparo todo para la recepcion del mensaje
                ObjectInputStream flujo = new ObjectInputStream(cliente.getInputStream());

                // recibo el mensaje
                mensaje = (Mensaje) flujo.readObject();

                // entrego el mensaje
                return mensaje;

            }
            catch (EOFException ex) {
                return null;
            }

            catch (ClassNotFoundException ex) {
                System.err.println("#####################\n");
                System.err.println(ex.getMessage());
                ex.printStackTrace();
                System.err.println("#####################\n");
            }
        }
        return null;

    }

    private static boolean checkFile(int fd, String nombreArchivo) {
        OpenFile fila = Stub.tabla.get(fd);
        if (fila != null) {
            return (fila.getNombreArchivo().compareTo(nombreArchivo) == 0);
        } else {
            return false;
        }
    }
}
